#ifndef GRPCEVENTCLIENT_H
#define GRPCEVENTCLIENT_H

#include <algorithm>
#include <memory>
#include <string>
#include <map>
#include <thread>
#include <queue>
#include <atomic>

#include "nlohmann/json.hpp"

#include <grpc/grpc.h>
#include <grpcpp/alarm.h>
#include <grpcpp/channel.h>
#include <grpcpp/client_context.h>
#include <grpcpp/create_channel.h>
#include <grpcpp/security/credentials.h>


#include "grpcevent.grpc.pb.h"


using grpc::Channel;
using grpc::ClientContext;
using grpc::ClientReader;
using grpc::ClientReaderWriter;
using grpc::ClientWriter;
using grpc::Status;
using Evol::Common::Grpc::Server::GrpcEvent;
using Evol::Common::Grpc::Server::GrpcEventMessage;

class GrpcEventDispatcher;


class Reader : public grpc::ClientReadReactor<GrpcEventMessage> {
public:
    Reader(GrpcEvent::Stub* stub, const std::string& parent);

    //启动读取事件
    void StartReadEvent();

    bool IsError();
    grpc::StatusCode GetErrStatus();

    void OnReadDone(bool ok) override ;

    void OnDone(const Status& s) override;

private:
    GrpcEvent::Stub* m_parentStub = nullptr;
    std::string m_parent;

    ClientContext m_context;
    GrpcEventMessage m_response;
    Status m_status;

    std::atomic_bool m_isError = false; //已经在读取中
    grpc::StatusCode m_errStatus; //外部线程在判断有错的时候才会读取该值，所以不用锁控制

};

class GrpcEventClient
{

public:
    GrpcEventClient(const std::string name, const std::string ip, const uint16_t port);

    ~GrpcEventClient();

    //参数一定是json 数组
    void SendEvent(const std::string& dst, const std::string& eventName, const nlohmann::json& array);

private:
    void readWriteThreadProc();

    void createConnection();

    bool checkStatusCanRecover(grpc::StatusCode code);
private:
    std::string m_name;
    std::string m_ip;
    uint16_t m_port = 0;
    std::shared_ptr<Channel> m_channel = nullptr;
    std::unique_ptr<GrpcEvent::Stub> m_stub = nullptr;

    std::unique_ptr<Reader> m_reader;

    bool m_stop = false;
    std::thread m_thread;

    std::mutex m_queueMutex;
    std::queue<GrpcEventMessage> m_eventQueue;


};

extern std::shared_ptr<GrpcEventClient> g_pGrpcClient;


#endif // GRPCEVENTCLIENT_H
